package isssr.dao.hibernate;

import isssr.dao.exception.DAOException;
import isssr.dao.exception.HibernateDAOException;
import isssr.dao.interfaces.RecordPagination;
import isssr.dao.interfaces.RecordSorting;
import isssr.dao.interfaces.RoleDAO;
import isssr.entity.src.Role;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;


import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.SimpleExpression;

public class HibernateRoleDAO extends HibernateDAOCommons implements RoleDAO, Serializable {

	public HibernateRoleDAO(SessionFactory sessionFactory)
	{
		super(sessionFactory);
	}
	
	@Override
	public void insert(Role role) throws DAOException {
		
		super.insert(role);

	}

	@Override
	public void update(Role role) throws DAOException {

		super.update(role);
	}

	@Override
	public void delete(Role role) throws DAOException {
		
		super.delete(role);
	}

	private void addPagingToCriteria(Criteria criteria, RecordPagination pagination) 
	{
		if(pagination == null)
			return;
		
		if(pagination.firstResult != null && pagination.firstResult > 0)
			criteria.setFirstResult(pagination.firstResult);
		
		if(pagination.pageSize != null && pagination.pageSize > 0)
			criteria.setFetchSize(pagination.pageSize);
	}

	private void addFilteringToCriteria(Criteria criteria, Map<String, Object> matchingFilters)
	{
		if(matchingFilters == null || matchingFilters.isEmpty())
		{
			return;
		}
		
		String label;
		Object value;
		Criterion criterion = null;
		
		for(Entry<String, Object> filter : matchingFilters.entrySet())
		{
			label = filter.getKey();
			value = filter.getValue();
			
			if(label.equals("title"))
			{
				criterion = Restrictions.like(label, (String) value, MatchMode.ANYWHERE);
				criteria.add(criterion);
			}
			else if(label.equals("description"))
			{
				criterion = Restrictions.like(label, (String) value, MatchMode.ANYWHERE);
				criteria.add(criterion);
			}
			else if(label.equals("level"))
			{
				criterion = Restrictions.eq(label, value);
				criteria.add(criterion);
			}
			
		}
		
	}
	

	private void addOrderingToCriteria(Criteria criteria, RecordSorting ordering) 
	{
		if(ordering == null || ordering.getField() == null)
			return;
		
		switch(ordering.getOrder())
		{
			case ASCENDING: 
				criteria.addOrder(Order.asc(ordering.getField()));
				break;
			case DESCENDING:
				criteria.addOrder(Order.desc(ordering.getField()));
				break;
		}
	}
	
	@Override
	public Role getByTitle(String title) throws HibernateDAOException {
		
		Session session = null;
		Transaction transaction;
		try
		{
			session = openSession();
			transaction = session.beginTransaction();
			
			Criteria criteria = session.createCriteria(Role.class);
			criteria.add(Restrictions.like("title", title, MatchMode.EXACT));
			
			Role role = (Role) criteria.uniqueResult();
			
			transaction.commit();
			
			return role;
		}
		catch(Exception ex)
		{
			String operationType = "GetByTitle";
			throw generateDAOException(ex, operationType);
		}
		finally
		{
			closeSession(session);
		}
	}

	@Override
	public Integer getAll(List<Role> results) throws DAOException {
		// TODO Auto-generated method stub
		return getAll(results, null, null, null);
	}

	@Override
	public Integer getAll(List<Role> results, Map<String, Object> matchingFilters,
			RecordSorting ordering, RecordPagination pagination)
			throws DAOException {


		Session session = null;
		
		try
		{
			session = openSession();
			
			Criteria criteria = session.createCriteria(Role.class);
			
			addFilteringToCriteria(criteria, matchingFilters);
			
			Number numberOfResults = countResultsByCriteria(criteria);
			
			addOrderingToCriteria(criteria, ordering);
			addPagingToCriteria(criteria, pagination);
			
			results.addAll(criteria.list());
			
			return numberOfResults.intValue();
		}
		catch(Exception ex)
		{
			String operationType = "GetAll";
			throw generateDAOException(ex, operationType);
		}
		finally
		{
			closeSession(session);
		}
	}


	private Number countResultsByCriteria(Criteria criteria) {
		
		criteria.setProjection(Projections.rowCount());
		
		Number resultCount = (Number) criteria.uniqueResult();
		
		resetProjectionsInCriteria(criteria);
		
		return resultCount;
	}

	private void resetProjectionsInCriteria(Criteria criteria) {
		criteria.setProjection(null);
		return;
	}
}
